package java_thinking.unit_21._21_5;

import java.util.concurrent.CountDownLatch;

/**
 * @Desc:   5-11 在计时测试中使用CountDownLatch 来启动和停止线程
 *              目的：同时释放所有线程，来测试所有线程同时并发开始到结束所需要的时间，
 *              可以测试线程执行的程序安全性，速度，并发压力等
 * @author: cww
 * @DateTime: 2019/6/5 19:30
 */

public class TestHarness {
    public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
        final CountDownLatch startGate = new CountDownLatch(1);
        final CountDownLatch endGate = new CountDownLatch(nThreads);
        for (int i = 0; i < nThreads; i++) {
            Thread t = new Thread() {
                @Override
                public void run() {
                    try {
                        //每个线程首先要做的是在启动门上等待，从而保证所有线程都就绪后才开始执行
                        //如果这里不进行 await 在线程 start 的时候就已经开始执行了，必须放在
                        //run 方法之前才能拒之门外
                        startGate.await();
                        try {
                            task.run();
                        } finally {
                            endGate.countDown();
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
            //await不能放这里，放这里就是主线程的门了，主线程会一直等待其状态变化
//            startGate.await();

            t.start();

        }
        long start = System.nanoTime();
        //startGate 在执行 countDown 方法后上面 nThreads 个线程任务才同时被释放，因为我们希望
        //测试n个线程并发执行某个任务时需要的时间，如果在创建每个线程后立即就启动了，那么先启动
        //的线程将“领先”后启动的线程，并且活跃线程数量会随着时间的推移而增加或减少，竞争程度也在
        //不断发生变化，
        startGate.countDown();
        //而结束门可以等待最后一个线程执行完成，而不是顺序等待；
        endGate.await();
        long end = System.nanoTime();
        return end-start;
    }
}

class DoSomething implements Runnable {

    @Override
    public void run() {
        System.out.println("do something");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class TestCountDownLatch {
    public static void main(String[] args) throws InterruptedException {
        long cost = new TestHarness().timeTasks(100,new DoSomething());
        System.out.println(cost);
    }
}
